

// =========================================
// ALSA 录音工具头文件
// 功能：封装 ALSA 设备管理和录音流程，支持 WAV 文件输出
// 作者：你的名字
// 日期：2025-09-17
// =========================================

#ifndef __BSP_ALSA_RECORDER_H
#define __BSP_ALSA_RECORDER_H

#include <alsa/asoundlib.h>
#include <string>
#include <vector>
#include <map>
#include <memory>

// WAV文件头结构（用于音频数据存储）
// 强制结构体按1字节对齐，确保与WAV文件格式一致
#pragma pack(push, 1)
/**
 * @brief WAV 文件头结构体
 * 用于标准 PCM WAV 文件头写入，确保录音数据可被主流播放器识别。
 */
struct WavHeader
{
    char riff[4];             // 标识RIFF文件格式，固定为"RIFF"
    uint32_t file_size;       // 整个文件大小（不包含riff字段的4字节）
    char wave[4];             // 标识WAVE文件，固定为"WAVE"
    char fmt[4];              // 标识fmt子块，固定为"fmt "
    uint32_t fmt_chunk_size;  // fmt子块大小（PCM格式固定为16）
    uint16_t audio_format;    // 音频格式（1表示PCM无损格式）
    uint16_t num_channels;    // 声道数（1=单声道，2=立体声）
    uint32_t sample_rate;     // 采样率（如44100Hz、48000Hz）
    uint32_t byte_rate;       // 码率（采样率×声道数×位深度/8）
    uint16_t block_align;     // 数据块对齐单位（声道数×位深度/8）
    uint16_t bits_per_sample; // 位深度（如16bit、24bit）
    char data[4];             // 标识data子块，固定为"data"
    uint32_t data_chunk_size; // 音频数据大小（总采样数×声道数×位深度/8）
};
// 恢复默认对齐方式
#pragma pack(pop)

// ALSA音频设备RAII管理类（自动释放设备句柄，避免内存泄漏）
/**
 * @brief ALSA 设备 RAII 管理类
 * 用于自动管理 snd_pcm_t* 句柄，防止资源泄漏。
 * 禁止拷贝，支持移动。
 */
class AlsaDevice
{
public:
    /**
     * @brief 构造函数，接收ALSA设备原始句柄
     * @param handle ALSA设备句柄（通过snd_pcm_open获取）
     */
    explicit AlsaDevice(snd_pcm_t *handle);

    /**
     * @brief 析构函数，自动关闭ALSA设备句柄
     */
    ~AlsaDevice();

    // 禁止拷贝构造和拷贝赋值（避免设备句柄重复释放）
    AlsaDevice(const AlsaDevice &) = delete;
    AlsaDevice &operator=(const AlsaDevice &) = delete;

    // 允许移动构造和移动赋值（支持句柄所有权转移）
    AlsaDevice(AlsaDevice &&other) noexcept;
    AlsaDevice &operator=(AlsaDevice &&other) noexcept;

    /**
     * @brief 获取原始ALSA设备句柄
     * @return snd_pcm_t* 设备句柄指针
     */
    snd_pcm_t *get() const;

    /**
     * @brief 重载类型转换运算符，直接返回设备句柄
     */
    operator snd_pcm_t *() const;

private:
    snd_pcm_t *handle_; // ALSA设备原始句柄
};

// ALSA音频录制工具类（封装录音核心逻辑）
/**
 * @brief ALSA 录音工具类
 * 封装录音参数设置、设备初始化、数据采集和 WAV 文件写入。
 * 支持命令行参数灵活配置。
 */
class AlsaRecorder
{
public:
    // 默认录音参数（可通过构造函数或setter修改）
    // 默认参数，便于快速录音测试和命令行解析
    static constexpr const char *DEFAULT_DEVICE = "default";                  ///< 默认音频设备
    static constexpr unsigned int DEFAULT_SAMPLE_RATE = 44100;                ///< 默认采样率（44.1kHz）
    static constexpr int DEFAULT_CHANNELS = 2;                                ///< 默认声道数（立体声）
    static constexpr snd_pcm_format_t DEFAULT_FORMAT = SND_PCM_FORMAT_S16_LE; ///< 默认格式（16位小端PCM）
    static constexpr int DEFAULT_DURATION = 5;                                ///< 默认录音时长（5秒）
    static constexpr const char *DEFAULT_FILENAME = "recording.wav";          ///< 默认输出文件名

    /**
     * @brief 构造函数，使用默认录音参数
     */
    AlsaRecorder();

    /**
     * @brief 构造函数，自定义录音参数
     * @param device 音频设备名称（如"default"、"hw:0,0"）
     * @param sample_rate 采样率（如44100、48000）
     * @param channels 声道数（1=单声道，2=立体声）
     * @param format 音频格式（参考ALSA格式枚举snd_pcm_format_t）
     * @param duration 录音时长（秒）
     * @param filename 输出WAV文件名
     */
    AlsaRecorder(const std::string &device,
                 unsigned int sample_rate,
                 int channels,
                 snd_pcm_format_t format,
                 int duration,
                 const std::string &filename);

    // 参数设置接口（支持动态修改录音参数）
    void set_device(const std::string &device) { device_ = device; }
    void set_sample_rate(unsigned int sample_rate) { sample_rate_ = sample_rate; }
    void set_channels(int channels) { channels_ = channels; }
    void set_format(snd_pcm_format_t format) { format_ = format; }
    void set_duration(int duration) { duration_ = duration; }
    void set_filename(const std::string &filename) { filename_ = filename; }

    /**
     * @brief 执行录音逻辑
     * @return bool 录音成功返回true，失败返回false
     */
    bool record(std::vector<uint8_t> &buffer);

    /**
     * @brief 获取ALSA格式对应的位深度
     * @param format ALSA音频格式（snd_pcm_format_t枚举值）
     * @return int 位深度（如16、24、32），失败返回0
     */
    static int get_bits_per_sample(snd_pcm_format_t format);

    /**
     * @brief 将格式字符串解析为ALSA格式枚举
     * @param format_str 格式字符串（如"S16_LE"、"U8"、"FLOAT_LE"）
     * @return snd_pcm_format_t 对应的ALSA格式，未知格式返回默认值
     */
    static snd_pcm_format_t parse_format(const std::string &format_str);

    /**
     * @brief 写入WAV文件头到输出流
     * @param file 二进制输出流（已打开的WAV文件）
     * @param sample_rate 采样率
     * @param channels 声道数
     * @param bits_per_sample 位深度
     * @param data_size 音频数据大小（字节）
     * @return bool 写入成功返回true，失败返回false
     */
    static bool write_wav_header(std::ofstream &file,
                                 uint32_t sample_rate,
                                 uint16_t channels,
                                 uint16_t bits_per_sample,
                                 uint32_t data_size);

public:
    // 格式字符串到ALSA格式的映射表（静态成员，全局共享）
    /**
     * @brief 格式字符串到 ALSA 枚举的映射表
     * 例如："S16_LE" -> SND_PCM_FORMAT_S16_LE
     * 用于命令行参数解析和格式兼容性扩展。
     */
    static const std::map<std::string, snd_pcm_format_t> format_map_;

private:
    /**
     * @brief 设置ALSA设备硬件参数（采样率、声道数、格式等）
     * @param handle ALSA设备句柄
     * @return bool 设置成功返回true，失败返回false
     */
    bool set_alsa_parameters(snd_pcm_t *handle) const;

    // 录音参数
    std::string device_;       // 音频设备名称
    unsigned int sample_rate_; // 采样率
    int channels_;             // 声道数
    snd_pcm_format_t format_;  // 音频格式
    int duration_;             // 录音时长（秒）
    std::string filename_;     // 输出WAV文件名
};

#endif // ALSA_RECORDER_H